以下文章已於 2021/09/16 轉移至 微笑之家
對於discord.js更新,或是有其他問題,都歡迎到以下網址查看喔
本站
本主題
本文章
昨天我們描繪了權限系統的架構,今天來建立身份組環境
打開我們之前的試算表,新增兩個table

UserPower
代表成員table
userID
discord的userID,主要用來辨識訊息方是否是此用戶
userName
用處一樣不大,給人看的
Joins
表示此用戶有哪些身份組的權限,筆者打算之後把所有身份都寫在這欄,用分號來做區隔
IsAdmin
管理員開關,開啟後不做任何身份組判斷,可以使用任何功能
下圖中,筆者的userID有E有+的,這是Excel自動給予的格式,可以在左上角看到實際數值,讀取時仍然是讀取165753385385984000,不用修改

PartyPower
代表身份組table
ID
該身份組的ID,使用者透過這個ID來判斷自己有哪些權限
type
代表這個身份組的類型
目前暫定1是禁言類身份組,2是tag權限身份組
Power
代表實際可行駛的權限,會根據type的不同有不同的含意
在tag權限下,Power帶入tagID,代表可以行使此tag
這邊帶入Power的是身份組ID

教一下手動獲取身份組ID
把人點開,對身份組右鍵

或是先拉出tag,然後在tag前方加上一個反斜線


如果以上操作遇到問題,甚至是UserID也抓不到
可以看一下這篇文章
或是找找怎麼開啟Discord的開發者模式
再來我們要新增兩個GAS檔案

function doGet(e) {
  var id = '你的ID'; //抓取表單
  var spreadsheet = SpreadsheetApp.openById(id); // Sheet id
  var sheet = spreadsheet.getSheetByName("UserPower"); // 根據表格名稱取表
  var rowLength = sheet.getLastRow()-1; //取行長度
  var columnLength = sheet.getLastColumn(); //取列長度
  var data = sheet.getRange(2,1,rowLength,columnLength).getValues(); // 取得的資料
  
  var dataExport = [];
  
  for(i in data){
    if(data[i][0] != ""){
    dataExport[i] = {
      userID:     data[i][0],
      userName:   data[i][1],
      Joins:   data[i][2],
      IsAdmin: data[i][3]
      }
    }
  }
  
  
  var dataExportFormat = JSON.stringify(dataExport);
  return ContentService.createTextOutput(dataExportFormat).setMimeType(ContentService.MimeType.JSON);
}

function doGet(e) {
  var id = '你的ID'; //抓取表單
  var spreadsheet = SpreadsheetApp.openById(id); // Sheet id
  var sheet = spreadsheet.getSheetByName("PartyPower"); // 根據表格名稱取表
  var rowLength = sheet.getLastRow()-1; //取行長度
  var columnLength = sheet.getLastColumn(); //取列長度
  var data = sheet.getRange(2,1,rowLength,columnLength).getValues(); // 取得的資料
  
  var dataExport = [];
  
  for(i in data){
    if(data[i][0] != ""){
    dataExport[i] = {
      ID:     data[i][0],
      type:   data[i][1],
      Power:   data[i][2]
      }
    }
  }
  
  
  var dataExportFormat = JSON.stringify(dataExport);
  return ContentService.createTextOutput(dataExportFormat).setMimeType(ContentService.MimeType.JSON);
}
記得都要存檔後,發佈成網路應用,獲取URL

(之前示範JSONArray的[],可以拿掉)
跟baseExcel一樣,我們會希望bot在啟動時就把表都讀取進來,從雲端下載成本地db的感覺,順便做資料二次處理

const userPower = {
    'method': 'GET',
    'url': auth.Gas.Get[0].UserPower,
    'headers': {}
};
const partyPower = {
    'method': 'GET',
    'url': auth.Gas.Get[0].PartyPower,
    'headers': {}
};


exports.getUserPower = function(callback) {
    let backValue = new Array;
    request(userPower, function(error, response) {
        try {
            if (error) {
                console.log('getUserPowerError1', error);
                callback(false);
            } else {
                const data = JSON.parse(response.body); //接收回傳(response)的body
                for (i in data) {
                    backValue.push(data[i]);
                    backValue[i].Joins = backValue[i].Joins.split(';');
                }
                callback(backValue);
            }
        } catch (err) {
            console.log('getUserPowerError2', err);
            callback(false);
        }
    });
};
exports.getPartyPower = function(callback) {
    let backValue = new Array;
    request(partyPower, function(error, response) {
        try {
            if (error) {
                console.log('getPartyPowerError1', error);
                callback(false);
            } else {
                const data = JSON.parse(response.body); //接收回傳(response)的body
                for (i in data) {
                    backValue.push(data[i]);
                    backValue[i].Power = backValue[i].Power.split(';');
                }
                callback(backValue);
            }
        } catch (err) {
            console.log('getPartyPowerError2', err);
            callback(false);
        }
    });
};

(開始變成callback地獄了)
資料都接到也處理好了,再來要用這些資料實作功能
增加指令列表的一個新系統

在message事件新增入口

然後做出實際功能

//#region tag系統
function TagFunction(msg, tempPrefix) {
    const cmd = msg.content.substring(prefix[tempPrefix].Value.length).split(' '); //以空白分割前綴以後的字串
    switch (cmd[0]) {
        case '其餘指令':
            break;
        default: //身份組ID
            CheckID(msg, cmd, CheckParty);
            break;
    }
}
//判斷此人有沒有登記資料
function CheckID(msg, cmd, OtherFunction) {
    const haveUserData = UserPowerData.find(element => {
        return element.userID == msg.author.id;
    })
    if (haveUserData !== undefined) {
        //有資料
        if (haveUserData.IsAdmin) {
            //是管理員,直接做後續事情
            return SendTagMessage(msg, `<@&${cmd[1]}>\n來自管理員<@${msg.author.id}>的指令呼叫`);
        } else {
            //不是管理員,先看有甚麼群組
            return OtherFunction(msg, cmd, haveUserData);
        }
    }
}
//根據UserPower獲得Party
function CheckParty(msg, cmd, haveUserData) {
    let havePartyPower;
    havePartyPower = PartyPowerData.filter(element => {
        if (haveUserData.Joins[i].indexOf(element.ID) != -1) {
            return element.Power.indexOf(cmd[1]) != -1
        }
    })
    if (isEmptyObject(havePartyPower)) {
        SendTagMessage(msg, '無權限,請確認參數是否正確');
    } else {
        SendTagMessage(msg, `<@&${cmd[1]}>\n來自<@${msg.author.id}>的指令呼叫`);
    }
}
//傳送訊息單獨實例
function SendTagMessage(msg, data) {
    msg.channel.send(data);
}
最後補個判斷Array是不是空集合的小function

大致解說一下

Tag系統的入口function
跟其他系統一樣,判斷要使用甚麼指令
今天先把預設(default)指令,也就是tag身分組做出來

檢查UserPower中是否有此人資料,以及是否是管理員
如果有資料且不是管理員,繼續檢查其所屬身份組權限

檢查身份組中是否有權限符合這次要tag的對象id,有的話代表此次指令滿足權限,給予tag
我們跑看看

成功